package com.bank.seckill.controller;

import com.bank.RabbitMQ.Producter;
import com.bank.entity.Member;
import com.bank.entity.Seckill;
import com.bank.entity.SeckillLog;
import com.bank.entity.vo.SeckillMessage;
import com.bank.entity.constant.ResponseEnum;
import com.bank.entity.vo.Response;
import com.bank.seckill.service.impl.GoodsServiceImpl;
import com.bank.seckill.service.impl.OrderServiceImpl;
import com.bank.um.service.Impl.MemberServiceImpl;
import com.baomidou.mybatisplus.extension.api.R;
import com.google.common.collect.Maps;
import com.mysql.cj.x.protobuf.MysqlxCrud;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author: Lixy
 * @email: 1908598362@qq.com
 * @date: 2022/1/28 星期五 17:48
 */

@RestController
@RequestMapping("/order")
@CrossOrigin
@Slf4j
public class OrderController implements InitializingBean {

    @Autowired
    private OrderServiceImpl orderService;

    @Autowired
    private GoodsServiceImpl goodsService;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedisScript redisScript;

    @Autowired
    private Producter producter;

    private static final Map<String, Boolean> IS_EMPTY_STOCK = Maps.newConcurrentMap();

//  PostMapping("/{path}/seckill")
    //public Response seckill(@PathVariable String path,Member member, String secid){
    @PostMapping("/seckill")
    public Response seckill(Member member, String secid) {
        log.info("seckillGoodsId: {}", secid);
        //Member member = memberService.SelectById(memid);
        //Seckill goods = goodsService.SelcetGoodsById(secId);
//        if (goods.getQuantity() < 1) {
//            return Response.response3(ResponseEnum.EMPTY_STOCK_ERROR, ResponseEnum.EMPTY_STOCK_ERROR.getMsg());
//        }

        //判断用户是否重复下单
        SeckillLog order = (SeckillLog) redisTemplate.opsForValue().get("order" + member.getId() + ":" + secid);
        //SeckillLog order = (SeckillLog) redisTemplate.opsForValue().get("order" + ":" + secid);

        //秒杀地址url的隐藏，拼接随机字符串
//        Boolean doCheck = orderService.checkPath(path, member, secid);
//        if (!doCheck){
//            return Response.response1(ResponseEnum.ERROR,-1,"非法的请求");
//        }

        if (order != null) {
            return Response.response1(ResponseEnum.GOODS_ALREADY_BUY, -1, ResponseEnum.GOODS_ALREADY_BUY.getMsg());
        }

        //decrby预减库存
        Long decrement = redisTemplate.opsForValue().decrement("seckillGoods:" + secid);

        //分布式锁预减库存解决超卖
        //Long decrement = (Long) redisTemplate.execute(redisScript, Collections.singletonList("seckillGoods:" + secid), Collections.EMPTY_LIST);

        if (decrement < 0) {
            IS_EMPTY_STOCK.put(secid, true);
            return Response.response3(ResponseEnum.EMPTY_STOCK_ERROR, ResponseEnum.EMPTY_STOCK_ERROR.getMsg());
        }
        //内存标记减少redis访问
        if (IS_EMPTY_STOCK.get(secid)) {
            return Response.response3(ResponseEnum.EMPTY_STOCK_ERROR, ResponseEnum.EMPTY_STOCK_ERROR.getMsg());
        }

        SeckillMessage seckillMessage = new SeckillMessage(member,secid);
        producter.SendSecMsg(seckillMessage);


        //int row = orderService.seckill(member, goods);
//        if (row > 0) {
//            return Response.response1(ResponseEnum.SUCCESS, secId, "秒杀成功");
//        } else {
//            return Response.response1(ResponseEnum.EMPTY_STOCK_ERROR, -1, ResponseEnum.EMPTY_STOCK_ERROR.getMsg());
//        }


        /**
         @param data：-1：下单失败   0：排队中  orderId：下单完成
         RabbitMQ一大作用 异步下单，流量削峰的体现，能够让我们在此处快速返回处理其他接口 不用等待订单创建完成
         生成了对应订单后返回，而是统一返回状态码0 即排队中，解决前期大量请求涌入问题，让MQ慢慢的处理 轮询返回客户端查询结果，有部分
         负载均衡的意思 (mq.maxmsg=10)
          * */
        return Response.response1(ResponseEnum.SUCCESS, 0, "秒杀排队中，请等待...");
    }

    @RequestMapping(value = "/result", method = RequestMethod.GET)
    @ResponseBody
    public Response getResult(Member member, String secid) {
//        if (member == null) {
//            return Response.response3(ResponseEnum.USER_NOT_LOGIN_ERROR, ResponseEnum.USER_NOT_LOGIN_ERROR.getMsg());
//        }
        String seckillorderId = orderService.getResult(member, secid);
        if (seckillorderId.equals("-1")) {
            return Response.response3(ResponseEnum.ERROR, "秒杀失败");
        } else if (seckillorderId.equals("0")) {
            return Response.response3(ResponseEnum.WAITING, "仍在排队中,请耐心等待");
        } else {
            return Response.response1(ResponseEnum.SUCCESS, seckillorderId, "秒杀成功");
        }
    }

    @PostMapping("/selectById")
    public Response selectById(String seckillorderId) {
        SeckillLog order = orderService.SelcetOrderById(seckillorderId);
        if (order == null) {
            return Response.response1(ResponseEnum.ERROR, -1, "订单为空,请退出重试");
        } else {
            return Response.response2(ResponseEnum.SUCCESS, order);
        }
    }

    @GetMapping("/path")
    public Response getPath(Member member,String secid){
        if (member==null){
            return Response.response3(ResponseEnum.USER_NOT_LOGIN_ERROR,ResponseEnum.USER_NOT_LOGIN_ERROR.getMsg());
        }
        String path = orderService.createPath(member, secid);
            return Response.response1(ResponseEnum.SUCCESS,path,ResponseEnum.SUCCESS.getMsg());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        List<Seckill> goods = goodsService.SelectAll();
        if (CollectionUtils.isEmpty(goods)) {
            return;
        }
        goods.forEach(seckill ->
                {
                    redisTemplate.opsForValue().set("seckillGoods:" + seckill.getSecid(), seckill.getQuantity());
                    IS_EMPTY_STOCK.put(seckill.getSecid(), false);

                }
        );
    }

}
